package com.example.httpclient.chapter1.section8;

import lombok.NonNull;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.HttpEntityWrapper;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 *
 * 使用ProcessEntityWrapper 包装了原生的 HttpEntity，同时引入监听器
 *      在原生的 HttpEntity 执行写入的时候使用自定义的 CountingOutputStream 包装原生的 OutputStream，同时继承监听器
 *      在原生的 OutputStream 执行写入操作时，统计字节数，并执行监听器中的方法进行进度的处理(打印、通知...)
 * @author zpMeng
 * @since 2024/6/17
 */
public class ProgressEntityWrapper extends HttpEntityWrapper {
    private final ProgressListener listener;

    public ProgressEntityWrapper(final HttpEntity entity, final ProgressListener listener) {
        super(entity);
        this.listener = listener;
    }

    @Override
    public void writeTo(final OutputStream outStream) throws IOException {
        super.writeTo(new CountingOutputStream(outStream, listener, getContentLength()));
    }

    public static class CountingOutputStream extends FilterOutputStream {

        private final ProgressListener listener;
        private long transferred;
        private final long totalBytes;

        CountingOutputStream(final OutputStream out, final ProgressListener listener, final long totalBytes) {
            super(out);
            this.listener = listener;
            transferred = 0;
            this.totalBytes = totalBytes;
        }

        @Override
        public void write(final byte @NonNull [] b, final int off, final int len) throws IOException {
            out.write(b, off, len);
            transferred += len;
            listener.progress(getCurrentProgress());
        }

        @Override
        public void write(final int b) throws IOException {
            out.write(b);
            transferred++;
            listener.progress(getCurrentProgress());
        }

        private float getCurrentProgress() {
            return ((float) transferred / totalBytes) * 100;
        }
    }
}
